package com.jin.jpa.wrapper.expression;

import com.jin.jpa.wrapper.LambdaWrapperContext;

import javax.persistence.criteria.Path;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Selection;

/**
 * @Author: yuanxiuyao
 * @Date: 2024/1/4 15:07
 * @PackageName: org.example.jpa.wrapper
 * @Version 1.0
 */
public class SelectExpression implements IExpression<Selection<?>>{

    private String field;

    private SelectOp selectOp;

    public SelectExpression(String field, SelectOp selectOp){
        this.field = field;
        this.selectOp = selectOp;
    }

    public static SelectExpression of(String field, SelectOp selectOp){
        return new SelectExpression(field, selectOp);
    }

    public Selection<?> toHandle(LambdaWrapperContext<?> context){
        switch (selectOp) {
            case SUM:
                return context.getCriteriaBuilder().sum(obtainNumberPath(context.getRoot()));
            case MIN:
                return context.getCriteriaBuilder().min(obtainNumberPath(context.getRoot()));
            case MAX:
                return context.getCriteriaBuilder().max(obtainNumberPath(context.getRoot()));
            case COUNT:
                return context.getCriteriaBuilder().count(obtainNumberPath(context.getRoot()));
            case NORMAL:
                return obtainPath(context.getRoot());
            default:
                return null;
        }
    }

    protected Path<?> obtainPath(Root<?> root){
        if(field.contains("\\.")) {
            String[] split = field.split("\\.");
            Path<?> path = null;
            for (String s : split) {
                path = root.get(s);
            }
            return path;
        } else {
            return root.get(field);
        }
    }

    protected <N extends Number> Path<N> obtainNumberPath(Root<?> root){
        if(field.contains("\\.")) {
            String[] split = field.split("\\.");
            Path<?> path = null;
            for (String s : split) {
                path = root.get(s);
            }
            return (Path<N>)path;
        } else {
            return root.get(field);
        }
    }

    public enum SelectOp{
        NORMAL,
        SUM,
        MAX,
        MIN,
        COUNT
    }
}
